#include "cc2dv2.h"
#include "csb.h"
#include "csbmath.h"

NS_CSB_BEGIN
/*********************| static data |*********************/
static bool			__cc2dv2_inited = false;
static cc2dv2*			__cc2dv2 = NULL;
static float			__def_fps = 0.0154f;

struct Bind2ELE_t {
	BindProto::bind_t*	b;
	BindProto::bindele_t*	e;
};

/*********************| extern C func |*********************/
void CCSize2CP(const CCSize& s, convex_polygon_t* out)
{
	CSB_NO_VRET(out);
	out->pnum = 4;
	const float w2 = s.width / 2.0f;
	const float h2 = s.height / 2.0f;
	out->points[0].x = out->points[3].x = -w2;
	out->points[0].y = out->points[1].y = h2;
	out->points[1].x = out->points[2].x = w2;
	out->points[2].y = out->points[3].y = -h2;
}

void CCRect2CP(const CCRect& rect, convex_polygon_t* out)
{
	CSB_NO_VRET(out);
	out->pnum = 4;
	const float w2 = rect.size.width / 2.0f;
	const float h2 = rect.size.height / 2.0f;
	CP_STACK_4(tmp);
	tmp.pnum = 4;
	tmp.points[0].x = tmp.points[3].x = -w2;
	tmp.points[0].y = tmp.points[1].y = h2;
	tmp.points[1].x = tmp.points[2].x = w2;
	tmp.points[2].y = tmp.points[3].y = -h2;
	elebase_t e;
	CCPoint mid = ccp(rect.getMidX(), rect.getMidY());
	COORD_POS_CONVERT(mid, e.pos);
	e.rotate = 0;
	e.scale.xs = e.scale.ys = 1.0f;
	elebase_coll_CP(&e, &tmp, out);
}

/*********************| static functions |*********************/
static void _bind_nodeBeginCB( csnode_t* pcs, void* udata)
{
	struct Bind2ELE_t* pb = (struct Bind2ELE_t*)(udata);
	pb->b->proto->onBegin(pb->b->fname.c_str(), pb->e);
}

static void _bind_nodeEndCB( csnode_t* pcs , void* udata)
{
	struct Bind2ELE_t* pb = (struct Bind2ELE_t*)(udata);
	pb->b->proto->onEnd(pb->b->fname.c_str(), pb->e);
}

static void _bind_objUpdateCB( csobj_t* po , void* udata)
{
	struct Bind2ELE_t* pb = (struct Bind2ELE_t*)(udata);
	pb->b->proto->onObjUpdate(pb->b->fname.c_str(), pb->e);
}

static void _bind_buBornCB(bullet_t* p, void* udata)
{
	struct Bind2ELE_t* pb = (struct Bind2ELE_t*)(udata);
	pb->b->proto->onBulletBorn(pb->b->fname.c_str(), p, pb->e);
}

static void _bind_buDeadCB(bullet_t* p, void* udata)
{
	struct Bind2ELE_t* pb = (struct Bind2ELE_t*)(udata);
	pb->b->proto->onBulletDead(pb->b->fname.c_str(), p, pb->e);
}

static int _bind_buUpdateCB(bullet_t* p, void* udata)
{
	struct Bind2ELE_t* pb = (struct Bind2ELE_t*)(udata);
	return pb->b->proto->onBulletUpdate(pb->b->fname.c_str(), p, pb->e);
}

static void _bind_autoMachine(pos_t* out, void* udata)
{
	struct Bind2ELE_t* pb = (struct Bind2ELE_t*)(udata);
	pb->b->proto->onAutoMachine(pb->b->fname.c_str(), pb->e, out);
}

static void csbfilename_head(const char* src, char* out)
{
	size_t l = strlen(src);
	while (l) {
		--l;
		if ('.' == src[l])
			break;
	}
	size_t t = 0;
	while (t < l) {
		if ('/' == src[t])
			break;
		++t;
	}
	++t;
	if (t >= l) {
		strncpy(out, src , l);
	} else {
		l -= t;
		strncpy(out, src + t, l);
	}
	out[l] = 0;
}

static int addobjdata_func(void** datare, void* flag)
{
	csobjdata_t* p = (csobjdata_t*)(*datare);
	((std::map<OBJ_DATA_MAP_TYPE>*)(flag))->insert(std::make_pair(std::string(p->name), p));
	return 1;
}

static void		liveJudge(BindProto::bindele_t* pb,  const size_t j1) {
	if (pb && pb->pcs->bulist.size <= j1 && CSB_FLAG_TEST(pb->pcs->ctlflag, NODE_CTL_STOP_EMIT) &&
		 CSB_FLAG_TEST(pb->pcs->ctlflag, NODE_CTL_STOP_OBJ) ) {
		pb->pcs->ctlflag = CSB_FLAG_OFF(pb->pcs->ctlflag, NODE_CTL_STOP_BULLET);
		pb->live = 0;
	}
}

static int remove_bu_node_fun(void** datare, void* flag)
{
	bullet_t* b = (bullet_t*)(*datare);
	if (b) {
		CCNode* pn = (CCNode*)b->udata;
		CCNode* ppn = (CCNode*)flag;
		if (pn) {
			ppn->removeChild(pn);
		}
	}
	return 1;
}

#ifdef CSB_DEBUG
void BindProto::showBulletDebugCP(bool show)
{
	CCScene* ps = CCDirector::sharedDirector()->getRunningScene();
	CSB_NO_VRET(ps);
	if (show) {
		if (_debugBuDrawNode && _debugBuDrawNode->getParent())
			return;
		_debugBuDrawNode = CCDrawNode::create();
		ps->addChild(_debugBuDrawNode);
	} else {
		if (!_debugBuDrawNode)
			return;
		_debugBuDrawNode->removeFromParent();
		_debugBuDrawNode = NULL;
	}
}

#endif

BindProto::bindele_t*BindProto::getEleN(BindProto::bind_t* pb, size_t n)
{
	if (pb && n < pb->eleList.size()) {
		std::list<BindProto::bindele_t*>::iterator it = pb->eleList.begin();
		while (n > 0) {
			--n;
			++it;
		}
		return (bindele_t*)(*it);
	}
	return NULL;
}

/*********************| function in DefaultBindProto |*********************/
void DefaultBindProto::updatePos(BindProto::bindele_t* p)
{
	CSB_NO_VRET(_bindNode);
	csobj_t* po = p->pcs->pobj;
	// 注意坐标转换
	if (CSB_FLAG_TEST(p->flag, BindProto::UPDATE_PASSIVE)) {
		// 被动的获取信息
		CCPoint tp = _bindNode->getPosition();
		tp.x += p->posOffset.x;
		tp.y += p->posOffset.y;
		COORD_POS_CONVERT(tp, po->ele.pos);
		po->ele.scale.xs = _bindNode->getScaleX();
		po->ele.scale.ys = _bindNode->getScaleY();
		csobj_set_rotate(po,_bindNode->getRotation() + p->angleOffset,p->pcs->pobjdata->type);
	} else {
		// 设置主动位置
		CCPoint tp;
		COORD_POS_CONVERT(po->ele.pos, tp);
		tp.x -= p->posOffset.x;
		tp.y -= p->posOffset.y;
		_bindNode->setPosition(tp);
		_bindNode->setScaleX(po->ele.scale.xs);
		_bindNode->setScaleY(po->ele.scale.ys);
		_bindNode->setRotation(po->ele.rotate - p->angleOffset);
	}
}

void DefaultBindProto::onBegin(const char* fname, bindele_t* p)
{
	updatePos(p);
}

void DefaultBindProto::onEnd(const char* fname, bindele_t* p)
{
	// 控制循环次数
	if (_endTarget && _endCall) {
		(_endTarget->*_endCall)(p);
	}
}

void DefaultBindProto::onObjUpdate(const char* fname, bindele_t* p)
{
	updatePos(p);
}

void DefaultBindProto::onBulletBorn(const char* fname, bullet_t* p, bindele_t* pb)
{
	if (CSB_FLAG_TEST(pb->flag, BindProto::FINAL))
		return;
	if (CSB_FLAG_TEST(pb->flag, BindProto::RM_BULLET_ATONCE))
		return;
	// 子弹出生的时候利用emitBullet获得一个计算节点
	CCNode* pn = _buProto.emitBullet(p->attr.ID, fname, pb->objdatana);
	if (pn) {
		CCPoint tp;
		COORD_POS_CONVERT(p->ele.pos, tp);
		pn->setPosition(tp);
		pn->setRotation(p->ele.rotate);
		pn->setScaleX(p->ele.scale.xs);
		pn->setScaleY(p->ele.scale.ys);
		_buNode->addChild(pn);
		p->udata = (void*)pn;
		// TODO:如果有出生动画，需要run一个动画
	}
}

void DefaultBindProto::onBulletDead(const char* fname, bullet_t* p, bindele_t* pb)
{
	CCNode* b = (CCNode*)p->udata;
	if (b) {
		/* 这是直接删除 */
		if (_buNode) {
			_buNode->removeChild(b);
		}
		/* 如果有渐隐，那么就需要run一个action */
		// NOTE:可能还需要在子弹消失的位置播放一个爆破动画
		// 判定子弹木有的时候关闭子弹刷新，并且设定自身死亡
		liveJudge(pb, 1);
	}
}

int DefaultBindProto::onBulletUpdate(const char* fname, bullet_t* p, bindele_t* pb)
{
	// 处理立刻删除活着的子弹的标志
	if (CSB_FLAG_TEST(pb->flag, BindProto::RM_BULLET_ATONCE))
		return 2;
	if (CSB_FLAG_TEST(pb->flag, BindProto::FINAL))
		return 2;
	// 获取子弹，修改的子弹Node的信息
	CCNode* bu = (CCNode*)p->udata;
	if (bu) {
		CCPoint tp;
		COORD_POS_CONVERT(p->ele.pos, tp);
		bu->setPosition(tp);
		bu->setRotation(p->ele.rotate);
		bu->setScaleX(p->ele.scale.xs);
		bu->setScaleY(p->ele.scale.ys);
	}

	// 子弹碰撞的判定
	if (_hitTarget && _hitTest)  {
		// 子弹碰撞的判定
		CP_STACK(bucp);
		CP_STACK(orcp);
		_buProto.orcp(p->attr.ID, fname, pb->objdatana, &orcp);
		elebase_coll_CP(&p->ele, &orcp, &bucp);
#ifdef CSB_DEBUG
		// 绘制子弹的多边形
		if (_debugBuDrawNode) {
			CCPoint ps[16];
			for (size_t i = 0; i < bucp.pnum; ++i) {
				ps[i].x = bucp.points[i].x;
				ps[i].y = bucp.points[i].y;
			}
			_debugBuDrawNode->drawPolygon(ps, bucp.pnum,ccc4f(1.0f, 0, 0, 0.2f),
			                              1, ccc4f(0,0,1.0f, 1.0f));

		}
#endif
		return (_hitTarget->*_hitTest)(&bucp);
	}
	return 1;
}

void DefaultBindProto::onAutoMachine(const char* fname, BindProto::bindele_t* b, pos_t* pos)
{
	if (_amTarget && _amCall) {
		(_amTarget->*_amCall)(pos);
	} else {
		pos->x = pos->y = 0.0f;
	}
	pos->x = COORD_X_CONVERT(pos->x);
	pos->y = COORD_Y_CONVERT(pos->y);
}

void DefaultBindProto::unbindMe(bind_t* pb, const int flag)
{
	bool final = CSB_FLAG_TEST(flag, BindProto::FINAL);
	if (pb && pb->proto == this && (_bindNode || final)) {
		_bindNode = NULL;
		BindProto::bindele_t* pe = NULL;
		if (_buNode && final) {
			// remove all bullets node
			struct Bind2ELE_t* p2;
			for (std::list<BindProto::bindele_t*>::iterator it = pb->eleList.begin();
			     it != pb->eleList.end(); ++it) {
				pe = *it;
				p2 = (struct Bind2ELE_t*)pe->pcs->cbs.udata;
				list_foreach(&pe->pcs->bulist, remove_bu_node_fun,(void*)_buNode);
				CC_SAFE_DELETE(p2);
				csnode_buf_return(pe->pcs);
				CC_SAFE_DELETE(pe);
			}
			_buNode = NULL;
			pb->eleList.clear();
		} else {
			for (std::list<BindProto::bindele_t*>::iterator it = pb->eleList.begin();
			     it != pb->eleList.end(); ++it) {
				pe = *it;
				pe->flag |= flag;
				pe->pcs->ctlflag = CSB_FLAG_ON(pe->pcs->ctlflag, NODE_CTL_STOP_OBJ | NODE_CTL_STOP_EMIT);
				liveJudge(pe, 0);
			}
		}
	}
}

void DefaultBindProto::clearBulletsOnce(BindProto::bind_t* pb)
{
	if (pb) {
		BindProto::bindele_t* pe = NULL;
		for (std::list<BindProto::bindele_t*>::iterator eit = pb->eleList.begin();
		     eit != pb->eleList.end(); ++eit) {
			pe = *eit;
			if (pe->pcs->bulist.size) {
				list_foreach(&pe->pcs->bulist, remove_bu_node_fun,(void*)_buNode);
				csnode_zero_bulist(pe->pcs);
			}
		}
	}
}

/*********************| function in cc2dv2 |*********************/
cc2dv2::cc2dv2 () : _timeScale(0)
{
	this->onEnter();
	this->onEnterTransitionDidFinish();
}

cc2dv2::~cc2dv2 ()
{
	this->unscheduleUpdate();
	unbindAll(true);
	unloadAll();
}

bool cc2dv2::init(const CCSize& winSize, CCScheduler* ps)
{
	CSB_YES_RET(__cc2dv2_inited, true);
	COORD_CONFIG_VIEW_WORLD(winSize.width, winSize.height);
	CSB_math_init();
	list_buf_init();
	csnode_buf_init();
	CSB_NO_RET(CSBERR_NOERR == csberrno, false);
	csobj_buf_init();
	CSB_NO_RET(CSBERR_NOERR == csberrno, false);
	// 生成单例
	cc2dv2::instance()->setScheduler(ps);
	// NOTE: more here
	__cc2dv2_inited = true;
	return true;
}

void cc2dv2::end()
{
	if (__cc2dv2_inited) {
		delete __cc2dv2;
		csnode_buf_end(false);
		csobj_buf_end(false);
		__cc2dv2_inited = false;
	}
}

cc2dv2*	cc2dv2::instance()
{
	CSB_YES_RET(__cc2dv2, __cc2dv2);
	__cc2dv2 = new cc2dv2();
	return __cc2dv2;
}

void cc2dv2::CSMakeObjDataName(const int etype, const uint32_t NO, char* out, const size_t outlen)
{
	if (outlen > 0) {
		memset(out, 0, outlen);
		const char* en = "";
		switch (etype) {
		case EMITTER:
			en = "em";
			break;
		case LASER:
			en = "la";
			break;
		}
		snprintf(out, outlen, "%s#%u", en, NO);
	}
}

void cc2dv2::setTargetFPS(unsigned int n)
{
	__def_fps = 1.0f / (float)n;
	CCDirector::sharedDirector()->setAnimationInterval(__def_fps);
	__def_fps -= 0.006f;
}

void cc2dv2::run(BindProto::bind_t* p, bool r, bool emitNow)
{
	if (p && !p->eleList.empty()) {
		// 有效性检测
		std::set<BindProto::bind_t*>::iterator pit = _bindSet.find(p);
		CSB_YES_VRET(_bindSet.end() == pit);
		// 遍历设置
		BindProto::bindele_t* e = NULL;
		if (r) {
			for (std::list<BindProto::bindele_t*>::iterator it = p->eleList.begin();
			     it != p->eleList.end(); ++it) {
				e = *it;
				e->flag = CSB_FLAG_ON(e->flag, CSB::BindProto::RUNNING);
				e->pcs->ctlflag = CSB_FLAG_TO(!emitNow, e->pcs->ctlflag, NODE_CTL_STOP_EMIT);
			}
		} else {
			for (std::list<BindProto::bindele_t*>::iterator it = p->eleList.begin();
			     it != p->eleList.end(); ++it) {
				e = *it;
				e->flag = CSB_FLAG_OFF(e->flag, CSB::BindProto::RUNNING);
				e->pcs->ctlflag = CSB_FLAG_TO(!emitNow, e->pcs->ctlflag, NODE_CTL_STOP_EMIT);
			}
		}
	}
}

void cc2dv2::run(BindProto::bind_t* p, size_t n, bool r, bool emitNow)
{
	// 有效性检测
	std::set<BindProto::bind_t*>::iterator pit = _bindSet.find(p);
	CSB_YES_VRET(_bindSet.end() == pit);
	// 遍历设置
	BindProto::bindele_t* e = BindProto::getEleN(p, n);
	if (e){
		e->flag = CSB_FLAG_TO(r, e->flag, CSB::BindProto::RUNNING);
		e->pcs->ctlflag = CSB_FLAG_TO(!emitNow, e->pcs->ctlflag, NODE_CTL_STOP_EMIT);
	}
}

void cc2dv2::setScheduler(CCScheduler* scheduler)
{
	if (scheduler) {
		CCNode::setScheduler(scheduler);
	} else {
		CCNode::setScheduler(CCDirector::sharedDirector()->getScheduler());
	}
	this->scheduleUpdate();
}

bool cc2dv2::loadfile(const char* path)
{
	CSB_NO_RET(__cc2dv2_inited && path, false);
	// 判断是否已经加载过此文件
	char fh[256] = {0};
	csbfilename_head(path, fh);
	std::map<std::string, std::map<OBJ_DATA_MAP_TYPE>* >::iterator it = _objsMap.find(fh);
	CSB_YES_RET(_objsMap.end() != it,  true);
	// 加载此文件
	unsigned long l= 0;
	unsigned char* data = CCFileUtils::sharedFileUtils()->getFileData(path, "rb", &l);
	list_t* objlist = load_csbdata(data);
	CC_SAFE_DELETE_ARRAY(data);
	if (objlist && objlist->size > 0) {
		std::map<OBJ_DATA_MAP_TYPE>* om = new std::map<OBJ_DATA_MAP_TYPE>();
		_objsMap.insert(std::make_pair(std::string(fh), om));
		// foreach read data
		list_foreach(objlist, addobjdata_func, (void*)om);
		list_free(objlist, NULL);
		return true;
	}
	return false;
}

bool cc2dv2::loadfile(const std::vector<const char*>& filesVec)
{
	for (size_t i = 0; i < filesVec.size(); ++i) {
		if (!loadfile(filesVec[i]))
			return false;
	}
	return true;
}

void cc2dv2::unloadobjdata(const char* fname, const char* objdatana)
{
	CSB_NO_VRET(__cc2dv2_inited && fname && objdatana);
	std::map<std::string , std::map<OBJ_DATA_MAP_TYPE>* >::iterator it = _objsMap.find(fname);
	CSB_YES_VRET(_objsMap.end() == it);
	std::map<OBJ_DATA_MAP_TYPE>* pm = it->second;
	std::map<OBJ_DATA_MAP_TYPE>::iterator pit = pm->find(objdatana);
	if (pm->end() != pit) {
		csobjdata_free(pit->second);
		pm->erase(pit);
	}
	if (pm->empty()) {
		delete pm;
		_objsMap.erase(it);
	}
}

void cc2dv2::unloadfile(const char* fname)
{
	CSB_NO_VRET(__cc2dv2_inited && fname);
	std::map<std::string , std::map<OBJ_DATA_MAP_TYPE>* >::iterator it = _objsMap.find(fname);
	CSB_YES_VRET(_objsMap.end() == it);
	std::map<OBJ_DATA_MAP_TYPE>* pm = it->second;
	for (std::map<OBJ_DATA_MAP_TYPE>::iterator pit = pm->begin(); pit != pm->end(); ++pit) {
		csobjdata_free(pit->second);
	}
	delete pm;
	_objsMap.erase(it);
}

void cc2dv2::unloadAll()
{
	CSB_NO_VRET(__cc2dv2_inited);
	std::map<OBJ_DATA_MAP_TYPE>* pm = NULL;
	std::map<OBJ_DATA_MAP_TYPE>::iterator pit;
	for(std::map<std::string , std::map<OBJ_DATA_MAP_TYPE>* >::iterator it = _objsMap.begin();
	    it != _objsMap.end(); ++it) {
		pm = it->second;
		for (pit = pm->begin(); pit != pm->end(); ++pit) {
			csobjdata_free(pit->second);
		}
		delete pm;
	}
	_objsMap.clear();
}

bool cc2dv2::bind(BindProto::bind_t* pb)
{
	CSB_NO_RET(__cc2dv2_inited && pb && pb->eleList.size(), false);
	// 获取csobjdata_t
	std::map<std::string , std::map<OBJ_DATA_MAP_TYPE>* >::iterator it = _objsMap.find(pb->fname);
	CSB_YES_RET(_objsMap.end() == it, false);
	std::map<OBJ_DATA_MAP_TYPE>* pm = it->second;
	// 检测是否存在已经绑定的节点
	std::map<OBJ_DATA_MAP_TYPE>::iterator pit ;
	BindProto::bindele_t* pele = NULL;
	csobjdata_t* pd = NULL;
	struct Bind2ELE_t* p2 = NULL;
	std::list<BindProto::bindele_t*>::iterator eit;
	for (eit = pb->eleList.begin(); eit != pb->eleList.end(); ++eit) {
		pele = *eit;
		if (pele->pcs) return false;
		pit = pm->find(pele->objdatana);
		if (pm->end() == pit) goto do_err;
		pd = pit->second;
		// 设定绑定
		p2 = new Bind2ELE_t;
		p2->b = pb;
		p2->e = pele;
		node_cb_t ncb = {
		        _bind_nodeBeginCB, _bind_nodeEndCB, _bind_objUpdateCB,
		        _bind_buBornCB, _bind_buDeadCB, _bind_buUpdateCB,
			_bind_autoMachine, {0, 0},(void*)p2
		};
		// 生成csnode
		pele->pcs = csnode_buf_rent(pd, &ncb, NODE_CTL_NONE);
		pele->live = 1;
		if(!pele->pcs) goto do_err;
	}
	// 插入到绑定控制map中
	_bindSet.insert(pb);
	return true;
do_err:
	CSB_LOG("绑定失败了!!\n");
	// 绑定失败，清除内存
	while (eit != pb->eleList.begin()) {
		pele = *eit;
		csnode_buf_return(pele->pcs);
		pele->live = 0;
		pele->pcs = NULL;
		--eit;
	}
	return false;
}

void cc2dv2::unbind(BindProto::bind_t* pb, bool rmBu, bool dofinal)
{
	CSB_NO_VRET(__cc2dv2_inited);
	// 判断是否绑定了这个结构
	std::set<BindProto::bind_t*>::iterator it = _bindSet.find(pb);
	CSB_YES_VRET(_bindSet.end() == it);
	pb->proto->unbindMe(pb, (rmBu ? BindProto::RM_BULLET_ATONCE : 0) |
			    (dofinal ? BindProto::FINAL : 0));

}

void cc2dv2::unbindAll(bool rmBu, bool dofinal)
{
	CSB_NO_VRET(__cc2dv2_inited);
	BindProto::bind_t* pb = NULL;
	std::set<BindProto::bind_t*>::iterator it;
	int flag = (rmBu ? BindProto::RM_BULLET_ATONCE : 0) | (dofinal ? BindProto::FINAL : 0);
	for (it = _bindSet.begin(); it != _bindSet.end(); ++it) {
		pb = *it;
		pb->proto->unbindMe(pb, flag);
	}
}

void cc2dv2::update(float dt)
{
	_timeScale += dt;
	if (_timeScale >= __def_fps) {
		_timeScale = 0;
		BindProto::bind_t* p = NULL;
		if (_bindSet.empty()) return;
		BindProto::bindele_t* pe = NULL;
		struct Bind2ELE_t* p2 = NULL;
		std::list<BindProto::bindele_t*>::iterator eit;
		for (std::set<BindProto::bind_t*>::iterator it = _bindSet.begin();
		     it != _bindSet.end();) {
			p = *it;
#ifdef CSB_DEBUG
			p->proto->clearDebugNode();
#endif
			for(eit = p->eleList.begin(); eit != p->eleList.end();) {
				pe = *eit;
				if (pe->live) {
					if (CSB_FLAG_TEST(pe->flag, BindProto::RUNNING))
						csnode_update(pe->pcs);
					++eit;
				} else {
					p2 = (struct Bind2ELE_t*)pe->pcs->cbs.udata;
					CC_SAFE_DELETE(p2);
					csnode_buf_return(pe->pcs);
					CC_SAFE_DELETE(pe);
					eit = p->eleList.erase(eit);
				}
			}
			if(p->eleList.empty()) {
				_bindSet.erase(it++);
				delete p->proto;
				free(p);
			} else {
				++it;
			}

		}
	}
}

void cc2dv2::kakaAllBulletsOnce()
{
	if (_bindSet.empty()) return;
	BindProto::bind_t* pb = NULL;
	for (std::set<BindProto::bind_t*>::iterator it = _bindSet.begin();
	     it != _bindSet.end();++it) {
		pb = *it;
		pb->proto->clearBulletsOnce(pb);
	}
}

NS_CSB_END
